﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using daStaticAnalyser.Analysers;
using daStaticAnalyser;
using daSyntaxAnalyser;
using daSyntaxAnalyser.SyntaxTree;
using daBase.Analyser;

namespace DifferentAnalizers
{
    [AnalyserDefaultSettings("Magic Numbers в операторе.", "Использование Magic Numbers вместо констант!", 50, "Все константы, смысл которых не ясен из их значения, необходимо задавать явно (с использованием ключевого слова const).")]
    public class MagicNumbersAnalyser : BaseStaticAnalyser
    {
        [Category("Особые")]
        [DisplayName("Исключения")]
        [Description("Числа, которые не относятся к Magic Numbers.")]
        public List<GoodNumber> GoodNumbers { get { return (settings as MagicNumbersSettings).GoodNumbers; } set { (settings as MagicNumbersSettings).GoodNumbers = value; } }

        /// <summary>
        /// Инициализация
        /// </summary>
        protected override void Init()
        {
            if (settings == null)
                settings = new MagicNumbersSettings();
            (settings as MagicNumbersSettings).GoodNumbers.Add(new GoodNumber(0));
            (settings as MagicNumbersSettings).GoodNumbers.Add(new GoodNumber(1));
            (settings as MagicNumbersSettings).GoodNumbers.Add(new GoodNumber(100));
            base.Init();
        }

        /// <summary>
        /// Проверка элемента
        /// </summary>
        /// <param name="Element">элемент</param>
        /// <returns>элемент - Magic Number</returns>
        private bool CheckElement(ExpressionElement Element)
        {
            return (Element is ConstExpressionElement) && !(settings as MagicNumbersSettings).GoodNumbers.Contains(new GoodNumber((Element as ConstExpressionElement).Tokens.Join()));
        }

        /// <summary>
        /// Собственно анализ
        /// </summary>
        /// <param name="e">параметр анализа</param>
        protected override void DoAnalyse(SyntaxTreeArgs e)
        {
            if (e.Element is CaseBlockStatementElement)
            {
                CaseBlockStatementElement block = e.Element as CaseBlockStatementElement;
                foreach (ExpressionElement param in block.Params)
                    if (CheckElement(param))
                    {
                        AddError(block.StartInfo, string.Format("{0}:...", block.Params.Join(", ")));
                        return;
                    }
            }
            else if (e.Element is BinaryExpressionElement)
            {
                BinaryExpressionElement Expr = e.Element as BinaryExpressionElement;
                switch (Expr.Type.Token)
                {
                    case DelphiTokens.Less:
                    case DelphiTokens.LessOrEqual:
                    case DelphiTokens.Equal:
                    case DelphiTokens.Greater:
                    case DelphiTokens.GreaterOrEqual:
                        if (CheckElement(Expr.Left) || CheckElement(Expr.Right))
                            AddError(e.Element.StartInfo, e.Element.ToString());
                        break;
                }
            }
            else if (e.Element is ForStatementElement)
            {
                ForStatementElement Loop = e.Element as ForStatementElement;
                if (CheckElement(Loop.Start) || CheckElement(Loop.End))
                    AddError(e.Element.StartInfo, string.Format("for {0}:={1} {2} {3} do ...", Loop.Iterator, Loop.Start, Loop.Type, Loop.End));
            }
        }
    }
}
